package com.dcy.znoa.common.util;

import com.dcy.znoa.common.util.pojo.JsonCommon;
import com.dcy.znoa.common.util.pojo.JsonForList;
import com.dcy.znoa.common.util.redis.JsonMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;


import javax.annotation.PostConstruct;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;


//@Slf4j
@Component
public class RedisClient
{
	//redis对应的key
	public static final String ALL_AREA = "allArea";//所有省市县
	public static final String COMP_DEP_PREFIX = "compDep_";//公司的部门集合，后面需要加公司ID：eg:compDep_1 代表ID为1的公司
	public static final String DYSMS_PREFIX = "dysms_";//阿里大于的短信前缀，后面需要加手机号码：eg:dysms_13012345678 代表手机号码为13012345678的公司

	private static Log log = LogFactory.getLog(RedisClient.class);

	private static JedisPool jedisPool;//非切片连接池


	private static String ip;
	@Value(value = "${redis.host}")
	public void setIp(String ip) {
		RedisClient.ip = ip;
	}

	private static int port;
	@Value(value = "${redis.port}")
	public void setPort(int port) {
		RedisClient.port = port;
	}

	private static int maxConn;
	@Value(value = "${redis.maxConn}")
	public void setMaxConn(int maxConn) {
		RedisClient.maxConn = maxConn;
	}

	private static int maxIdle;
	@Value(value = "${redis.maxIdle}")
	public void setMaxIdle(int maxIdle) {
		RedisClient.maxIdle = maxIdle;
	}

	private static int minIdle;
	@Value(value = "${redis.minIdle}")
	public void setMinIdle(int minIdle) {
		RedisClient.minIdle = minIdle;
	}

	private static int timeout;
	@Value(value = "${redis.timeout}")
	public void setTimeout(int timeout) {
		RedisClient.timeout = timeout;
	}

	private static boolean testOnBorrow;
	@Value(value = "${redis.testOnBorrow}")
	public void setTestOnBorrow(boolean testOnBorrow) {
		RedisClient.testOnBorrow = testOnBorrow;
	}

	private static boolean testOnReturn;
	@Value(value = "${redis.testOnReturn}")
	public void setTestOnReturn(boolean testOnReturn) {
		RedisClient.testOnReturn = testOnReturn;
	}

	private static String passwd;
	@Value(value = "${redis.pass}")
	public void setPasswd(String passwd) {
		RedisClient.passwd = passwd;
	}

	@PostConstruct
	public void init()
	{
		try
		{
			JedisPoolConfig config = new JedisPoolConfig();
			// 控制一个pool可分配多少个jedis实例,通过pool.getResource()来获取;
			// 如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
			config.setMaxTotal(maxConn);

			// 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例。
			config.setMaxIdle(maxIdle);
			config.setMinIdle(minIdle);
			// 表示当borrow(引入)一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛出JedisConnectionException;
			config.setMaxWaitMillis(timeout);
			// 在borrow一个jedis实例时,是否提前进行validate操作；如果为true,则得到的jedis实例均是可用的;
			// 当调用borrow Object方法时,是否进行有效性检查
			config.setTestOnBorrow(testOnBorrow);
			// 当调用Return Object方法时,是否进行有效性检查
			config.setTestOnReturn(testOnReturn);

			//Idle时进行连接扫描
			config.setTestWhileIdle(true);
			//表示idle object evitor两次扫描之间要sleep的毫秒数
			config.setTimeBetweenEvictionRunsMillis(30000);
			//表示idle object evitor每次扫描的最多的对象数
			config.setNumTestsPerEvictionRun(10);
			//表示一个对象至少停留在idle状态的最短时间，然后才能被idle object evitor扫描并驱逐；这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义
			config.setMinEvictableIdleTimeMillis(60000);

//			jedisPool = new JedisPool(config, ip, port, timeout, passwd);
			jedisPool = new JedisPool(config, ip, port);
			log.info("init redis success!");
		}
		catch (Exception e)
		{
			log.error("init redis fail!", e);
			throw e;
		}
	}

	@Deprecated
	public static void putByte(byte[] key, byte[] value)
	{
		Jedis jedis = RedisClient.getConnect();
		jedis.set(key, value);
		releaseConnect(jedis);
	}

	@Deprecated
	public static byte[] getByte(byte[] key)
	{
		Jedis jedis = RedisClient.getConnect();
		byte[] result = jedis.get(key);
		releaseConnect(jedis);
		return result;
	}

//	@Deprecated
	public static void putString(String key, String value)
	{
		Jedis jedis = RedisClient.getConnect();
		jedis.set(key, value);
		releaseConnect(jedis);
	}

	public static void putString(String key, String value,long seconds)
	{
		Jedis jedis = RedisClient.getConnect();
		jedis.set(key, value);
		jedis.expire(key, (int) seconds);
//		jedis.expireAt(key,seconds*1000);
//		jedis.close();
		releaseConnect(jedis);

//		Jedis curJedis = RedisClient.getConnect();
//		curJedis.set(key,  JsonMapper.toLogJson(list));
//		curJedis.close();
	}

	@Deprecated
	public static void putList(String key, List<String> list)
	{
		Jedis jedis = RedisClient.getConnect();
		jedis.lpush(key, list.toArray(new String[list.size()]));
		releaseConnect(jedis);
	}

	@Deprecated
	//map 里面的key 对应的value 不能为空值
	public static void putMap(String key, Map<String, String> map)
	{
		Jedis jedis = RedisClient.getConnect();
		jedis.hmset(key, map);
		releaseConnect(jedis);
	}

//	@Deprecated
	public static void delByKey(String key)
	{
		Jedis jedis = RedisClient.getConnect();
		jedis.del(key);
		releaseConnect(jedis);
	}

	@Deprecated
	public static void expire(String key, int seconds)
	{
		Jedis jedis = RedisClient.getConnect();
		jedis.expire(key, seconds);//按秒计算
		releaseConnect(jedis);
	}

//	@Deprecated
	public static String get(String key)
	{
		Jedis jedis = RedisClient.getConnect();
		String result = jedis.get(key);
		releaseConnect(jedis);
		return result;
	}

	@Deprecated
	public static Map<String, String> getMap(String key)
	{
		Jedis jedis = RedisClient.getConnect();
		Map<String, String> result = jedis.hgetAll(key);
		releaseConnect(jedis);
		return result;
	}

	@Deprecated
	public static List<String> getList(String key)
	{
		Jedis jedis = RedisClient.getConnect();
		List<String> result = jedis.lrange(key, 0, -1);
		releaseConnect(jedis);
		return result;
	}

	/**
	 * 获取对象池对象
	 *
	 * @return
	 * @throws Exception
	 */
	public static Jedis getConnect()
	{
		try
		{
//			if (jedisPool == null)
//			{jedisPoolReset();}
			if (jedisPool == null)
				return null;

				return jedisPool.getResource();
		}
		catch (Exception e)
		{
			log.error("Get jedis connect fail!" + e);
			jedisPoolReset();
			try
			{
				if (jedisPool == null)
					return null;
				return jedisPool.getResource();
			}
			catch (Exception ex)
			{
//				throw ex;
				log.error("Jedis getConnect:"+ex.getMessage());
				return null;
			}
		}
	}

	/**
	 * 释放对象池对象
	 *
	 * @param connnect
	 */
//	@Deprecated
	public static void releaseConnect(Jedis connnect)
	{
		connnect.close();
//		jedisPool.returnResource(connnect);
	}

	/**
	 * jedis连接池重置
	 */
	public static void jedisPoolReset() {
		//JedisPool jedisPool = JedisUtil.getJedisPool();
		try {
			jedisPool.destroy();
		} catch (Exception e) {
		}
		try
		{
			JedisPoolConfig config = new JedisPoolConfig();
			// 控制一个pool可分配多少个jedis实例,通过pool.getResource()来获取;
			// 如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
			config.setMaxTotal(maxConn);

			// 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例。
			config.setMaxIdle(maxIdle);
			config.setMinIdle(minIdle);
			// 表示当borrow(引入)一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛出JedisConnectionException;
			config.setMaxWaitMillis(timeout);
			// 在borrow一个jedis实例时,是否提前进行validate操作；如果为true,则得到的jedis实例均是可用的;
			// 当调用borrow Object方法时,是否进行有效性检查
			config.setTestOnBorrow(testOnBorrow);
			// 当调用Return Object方法时,是否进行有效性检查
			config.setTestOnReturn(testOnReturn);

			//Idle时进行连接扫描
			config.setTestWhileIdle(true);
			//表示idle object evitor两次扫描之间要sleep的毫秒数
			config.setTimeBetweenEvictionRunsMillis(30000);
			//表示idle object evitor每次扫描的最多的对象数
			config.setNumTestsPerEvictionRun(10);
			//表示一个对象至少停留在idle状态的最短时间，然后才能被idle object evitor扫描并驱逐；这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义
			config.setMinEvictableIdleTimeMillis(60000);

			jedisPool = new JedisPool(config, ip, port, timeout, passwd);

			log.info("reinit redis success!");
		}
		catch (Exception e)
		{
			log.error("reinit redis fail!", e);
			throw e;
		}
	}

	public static  JsonForList getJsonListfromRedisOfByte(String key) throws IllegalAccessException, InstantiationException, UnsupportedEncodingException {
		//redis中查询
		Jedis jedis = RedisClient.getConnect();
		if(jedis==null){return  null;}
		byte[] valueByte = jedis.get(key.getBytes("UTF-8"));
		jedis.close();
		if(valueByte!=null){
			List value = (List)SerializeUtil.unserialize(valueByte);
//			T value =   (T) SerializeUtil.unserialize(valueByte);
			return  new JsonForList(value,JsonCommon.SUCCESS_CODE,JsonCommon.SUCCESS_MSG);
		}
		return null;
	}

	public static void putListToRedisOfByte(String key,List list) throws IllegalAccessException, InstantiationException, UnsupportedEncodingException {
		Jedis curJedis = RedisClient.getConnect();
		if(curJedis== null){
			log.error("putListToRedisOfByte error because of RedisClient.getConnect() exception");
			return;
		}
		curJedis.set(key.getBytes("UTF-8"), SerializeUtil.serialize(list));
		curJedis.close();
	}

	public static  JsonForList getJsonListfromRedisOfJson(String key) throws IllegalAccessException, InstantiationException {
		//redis中查询
		Jedis jedis = RedisClient.getConnect();
		String jsonStr = jedis.get(key);
		jedis.close();
		if(jsonStr!=null){
			List value = JsonMapper.buildNonDefaultMapper().fromJson(jsonStr, List.class);
			return  new JsonForList(value,JsonCommon.SUCCESS_CODE,JsonCommon.SUCCESS_MSG);
		}
		return null;
	}

	public static void putListToRedisOfJson(String key,List list) throws IllegalAccessException, InstantiationException {
		Jedis curJedis = RedisClient.getConnect();
		curJedis.set(key,  JsonMapper.toLogJson(list));
		curJedis.close();
	}

	// 暂时不搞 放 和 插入 json pojo 到 redis

	public static void main(String args[]){
		putString("1","2");
		String as = get("1");
		System.out.println(as);
	}

}